package com.example.elinkdemo;

import android.Manifest;
import android.app.Activity;
import android.app.Dialog;
import android.app.Dialog;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Paint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.baidu.tts.chainofresponsibility.logger.LoggerProxy;
import com.baidu.tts.client.SpeechSynthesizer;
import com.baidu.tts.client.SpeechSynthesizerListener;
import com.baidu.tts.client.TtsMode;
import com.example.elinkdemo.control.InitConfig;
import com.example.elinkdemo.listener.UiMessageListener;
import com.example.elinkdemo.util.Auth;
import com.example.elinkdemo.util.AutoCheck;
import com.example.elinkdemo.util.CommUtils;
import com.example.elinkdemo.util.FileUtil;
import com.example.elinkdemo.util.IOfflineResourceConst;
import com.example.elinkdemo.util.PinyinUtil;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import pub.devrel.easypermissions.EasyPermissions;


public class MainActivity extends BaseActivity implements IOfflineResourceConst {

    private static final String TAG = "MainActivity";
    private TextView textView;
    private Spannable spannableText;


    private static final String TEXT = "欢迎使用百度语音合成，请在代码中修改合成文本";


    // ================== 精简版初始化参数设置开始 ==========================
    /**
     * 发布时请替换成自己申请的appId appKey 和 secretKey。注意如果需要离线合成功能,请在您申请的应用中填写包名。
     * 本demo的包名是com.baidu.tts.sample，定义在build.gradle中。
     */
    protected String appId;

    protected String appKey;

    protected String secretKey;

    protected String sn; // 纯离线合成SDK授权码；纯在线合成SDK没有此参数

    // TtsMode.MIX; 离在线融合模式,在线优先 （纯离线sdk）； TtsMode.ONLINE 纯在线；  TtsMode.OFFLINE纯离线（纯离线sdk）
    private TtsMode ttsMode = IOfflineResourceConst.DEFAULT_SDK_TTS_MODE;

    private boolean isOnlineSDK = TtsMode.ONLINE.equals(IOfflineResourceConst.DEFAULT_SDK_TTS_MODE);
    // ================ 纯在线sdk或者选择TtsMode.ONLINE  以下参数无用;
    private static final String TEMP_DIR = "/sdcard/baiduTTS"; // 重要！请手动将assets目录下的3个dat 文件复制到该目录

    // 请确保该PATH下有这个文件
    private static final String TEXT_FILENAME = TEMP_DIR + "/" + IOfflineResourceConst.TEXT_MODEL;

    // 请确保该PATH下有这个文件 ，m15是离线男声
    private static final String MODEL_FILENAME = TEMP_DIR + "/" + IOfflineResourceConst.VOICE_MALE_MODEL;

    // ===============初始化参数设置完毕，更多合成参数请至getParams()方法中设置 =================

    protected SpeechSynthesizer mSpeechSynthesizer;

    // =========== 以下为UI部分 ==================================================

    private TextView mShowText;
    protected Handler mainHandler;
    private String desc; // 说明文件
    private Dialog mDialog;


    @Override
    protected int getLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    protected void initView() {
        textView = findViewById(R.id.textView);
        Object textObject = textView.getText();
        //Spannable spannableText;
        if (textObject instanceof Spannable) {
            spannableText = (Spannable) textObject;
        } else if (textObject instanceof String) {
            spannableText = new SpannableString((String) textObject);
        } else {
            // 可以根据实际情况进行其他类型的处理，或者抛出异常表示不支持的文本类型
            Log.d(TAG, "不支持的文本类型");
        }
    }

    @Override
    protected void initData() {
        initPermission();
        initBaidu();

//        new Thread(this::initTTs).start();
        initTTs();
        reqPermission();

//        showProgressDialog("初始化中，请稍后...");

//        try {
//            new Handler().postDelayed(new Runnable() {
//                @Override
//                public void run() {
//                    showInitLoading();
//                    PinyinUtil.getPinyin("王");
//                    cDialog.dismiss();
//                }
//            }, 100);
//
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        showPinyin("王");
//        mDialog.dismiss();
//        PinyinUtil.getPinyin("王");
//        hideProgressDialog();
    }


    private void showInitLoading() {
        // 创建自定义对话框
        cDialog = new Dialog(MainActivity.this);
        cDialog.setContentView(R.layout.layout_loading);
        // 显示对话框
        cDialog.show();
    }

    /**
     * 注意此处为了说明流程，故意在UI线程中调用。
     * 实际集成中，该方法一定在新线程中调用，并且该线程不能结束。具体可以参考NonBlockSyntherizer的写法
     */
    private void initTTs() {
        LoggerProxy.printable(true); // 日志打印在logcat中
        boolean isSuccess;
        if (!isOnlineSDK) {
            // 检查2个离线资源是否可读
            isSuccess = checkOfflineResources();
            if (!isSuccess) {
                return;
            } else {
                Log.d(TAG, "离线资源存在并且可读, 目录：" + TEMP_DIR);
            }
        }
        // 日志更新在UI中，可以换成MessageListener，在logcat中查看日志
        SpeechSynthesizerListener listener = new UiMessageListener(mainHandler);

        // 1. 获取实例
        mSpeechSynthesizer = SpeechSynthesizer.getInstance();
        mSpeechSynthesizer.setContext(this);

        // 2. 设置listener
        mSpeechSynthesizer.setSpeechSynthesizerListener(listener);

        // 3. 设置appId，appKey.secretKey
        int result = mSpeechSynthesizer.setAppId(appId);
        checkResult(result, "setAppId");
        result = mSpeechSynthesizer.setApiKey(appKey, secretKey);
        checkResult(result, "setApiKey");

        // 4. 如果是纯离线SDK需要离线功能的话
        if (!isOnlineSDK) {
            // 文本模型文件路径 (离线引擎使用)， 注意TEXT_FILENAME必须存在并且可读
            mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, TEXT_FILENAME);
            // 声学模型文件路径 (离线引擎使用)， 注意TEXT_FILENAME必须存在并且可读
            mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, MODEL_FILENAME);

            mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_MIX_MODE, SpeechSynthesizer.MIX_MODE_DEFAULT);
            // 该参数设置为TtsMode.MIX生效。
            // MIX_MODE_DEFAULT 默认 ，wifi状态下使用在线，非wifi离线。在线状态下，请求超时6s自动转离线
            // MIX_MODE_HIGH_SPEED_SYNTHESIZE_WIFI wifi状态下使用在线，非wifi离线。在线状态下， 请求超时1.2s自动转离线
            // MIX_MODE_HIGH_SPEED_NETWORK ， 3G 4G wifi状态下使用在线，其它状态离线。在线状态下，请求超时1.2s自动转离线
            // MIX_MODE_HIGH_SPEED_SYNTHESIZE, 2G 3G 4G wifi状态下使用在线，其它状态离线。在线状态下，请求超时1.2s自动转离线
        }
        // 5. 以下setParam 参数选填。不填写则默认值生效
        // 设置在线发声音人： 0 普通女声（默认） 1 普通男声  3 情感男声<度逍遥> 4 情感儿童声<度丫丫>
        mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, "0");
        // 设置合成的音量，0-15 ，默认 5
        mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_VOLUME, "9");
        // 设置合成的语速，0-15 ，默认 5
        mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEED, "5");
        // 设置合成的语调，0-15 ，默认 5
        mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_PITCH, "5");

        // mSpeechSynthesizer.setAudioStreamType(AudioManager.MODE_IN_CALL); // 调整音频输出

        if (sn != null) {
            // 纯离线sdk这个参数必填；在线sdk没有此参数
            mSpeechSynthesizer.setParam(IOfflineResourceConst.PARAM_SN_NAME, sn);
        }

        // x. 额外 ： 自动so文件是否复制正确及上面设置的参数
        Map<String, String> params = new HashMap<>();
        // 复制下上面的 mSpeechSynthesizer.setParam参数
        // 上线时请删除AutoCheck的调用
        if (!isOnlineSDK) {
            params.put(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, TEXT_FILENAME);
            params.put(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, MODEL_FILENAME);
        }

        // 检测参数，通过一次后可以去除，出问题再打开debug
        InitConfig initConfig = new InitConfig(appId, appKey, secretKey, ttsMode, params, listener);
        AutoCheck.getInstance(getApplicationContext()).check(initConfig, new Handler() {
            @Override
            /**
             * 开新线程检查，成功后回调
             */
            public void handleMessage(Message msg) {
                if (msg.what == 100) {
                    AutoCheck autoCheck = (AutoCheck) msg.obj;
                    synchronized (autoCheck) {
                        String message = autoCheck.obtainDebugMessage();
                        Log.d(TAG, message); // 可以用下面一行替代，在logcat中查看代码
                        // Log.w("AutoCheckMessage", message);
                    }
                }
            }

        });

        // 6. 初始化
        result = mSpeechSynthesizer.initTts(ttsMode);
        checkResult(result, "initTts");

    }


    private void speak(String msg) {
        /* 以下参数每次合成时都可以修改
         *  mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, "0");
         *  设置在线发声音人： 0 普通女声（默认） 1 普通男声  3 情感男声<度逍遥> 4 情感儿童声<度丫丫>
         *  mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_VOLUME, "5"); 设置合成的音量，0-15 ，默认 5
         *  mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEED, "5"); 设置合成的语速，0-15 ，默认 5
         *  mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_PITCH, "5"); 设置合成的语调，0-15 ，默认 5
         *
         */
//        new Thread(new Runnable() {
//            @Override
//            public void run() {

        if (mSpeechSynthesizer == null) {
            Log.d(TAG, "[ERROR], 初始化失败");
            return;
        }
        Log.d(TAG, "需要播放的文字为：" + msg);
        int result = mSpeechSynthesizer.speak(msg);
        // mShowText.setText("");
//        Log.d(TAG, "合成并播放 按钮已经点击");
//        checkResult(result, "speak");

//            }
//        }).start();

    }

    private void stop() {
        Log.d(TAG, "停止合成引擎 按钮已经点击");
        if (mSpeechSynthesizer != null) {
            int result = mSpeechSynthesizer.stop();
            checkResult(result, "stop");
        }

    }

    /**
     * 在线SDK不需要调用，纯离线SDK会检查资源文件
     * <p>
     * 检查 TEXT_FILENAME, MODEL_FILENAME 这2个文件是否存在，不存在请自行从assets目录里手动复制
     *
     * @return 检测是否成功
     */
    private boolean checkOfflineResources() {
        String[] filenames = {TEXT_FILENAME, MODEL_FILENAME};
        for (String path : filenames) {
            File f = new File(path);
            if (!f.canRead()) {
                Log.d(TAG, "[ERROR] 文件不存在或者不可读取，请从demo的assets目录复制同名文件到："
                        + f.getAbsolutePath());
                Log.d(TAG, "[ERROR] 初始化失败！！！");
                return false;
            }
        }
        return true;
    }


    private void checkResult(int result, String method) {
        if (result != 0) {
            Log.d(TAG, "error code :" + result + " method:" + method);
        }
    }

    private void initBaidu() {

        appId = Auth.getInstance(this).getAppId();
        appKey = Auth.getInstance(this).getAppKey();
        secretKey = Auth.getInstance(this).getSecretKey();
        sn = Auth.getInstance(this).getSn(); // 纯离线合成必须有此参数；在线合成SDK没有此参数
        desc = FileUtil.getResourceText(this, R.raw.mini_activity_description);
        mainHandler = new Handler() {
            /*
             * @param msg
             */
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (msg.obj != null) {
                    Log.d(TAG, msg.obj.toString());
                }
            }

        };
    }


    /**
     * android 6.0 以上需要动态申请权限
     */
    private void initPermission() {
        String[] permissions = {
                android.Manifest.permission.INTERNET,
                android.Manifest.permission.ACCESS_NETWORK_STATE,
                android.Manifest.permission.MODIFY_AUDIO_SETTINGS,
                android.Manifest.permission.WRITE_SETTINGS,
                android.Manifest.permission.ACCESS_WIFI_STATE,
                android.Manifest.permission.READ_EXTERNAL_STORAGE
                , android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.RECORD_AUDIO,
                Manifest.permission.WRITE_EXTERNAL_STORAGE // demo使用
        };

        ArrayList<String> toApplyList = new ArrayList<String>();

        for (String perm : permissions) {
            if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(this, perm)) {
                toApplyList.add(perm);
                // 进入到这里代表没有权限.
            }
        }
        String[] tmpList = new String[toApplyList.size()];
        if (!toApplyList.isEmpty()) {
            ActivityCompat.requestPermissions(this, toApplyList.toArray(tmpList), 123);
        }

    }


    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        // 此处为android 6.0以上动态授权的回调，用户自行实现。
    }


    String[] perms = {android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.WRITE_EXTERNAL_STORAGE
            , android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.RECORD_AUDIO};

    private static final int RC_CAMERA_PERM = 33;

    private static final int OVERLAY_PERMISSION_REQUEST_CODE = 1;

    private void reqPermission() {

        //EasyPermissions.hasPermissions()


        if (EasyPermissions.hasPermissions(this, perms)) {
            // 权限已授予，执行相关操作
            //startCamera();
        } else {
            // 请求权限
            EasyPermissions.requestPermissions(this, "权限申请", RC_CAMERA_PERM, perms);
        }

    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == RC_CAMERA_PERM) {
            // 检查是否有权限
            Log.d(TAG, "授权结果: " + resultCode);
        }

    }


    int startX = 0;
    int startY = 0;

    private Layout layout;

    int downX = 0;
    int downY = 0;

    int moveX = 0;
    int moveY = 0;

    int upX = 0;
    int upY = 0;

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        // 处理触摸事件

        switch (ev.getAction()) {

            case MotionEvent.ACTION_DOWN:

                downX = (int) ev.getX();
                downY = (int) ev.getY();

                break;

            case MotionEvent.ACTION_MOVE:

//                moveX = (int) ev.getX();
//                moveY = (int) ev.getY();
//
//                int moveAbsX = Math.abs(moveX - downX);
//                int moveAbsY = Math.abs(moveY - downY);

//                Log.d(TAG, "移动的x ===>>> " + moveAbsX + ",======> " + moveAbsY);

                break;

            case MotionEvent.ACTION_UP:

                upX = (int) ev.getX();
                upY = (int) ev.getY();

                int upAbsX = Math.abs(upX - downX);
                int upAbsY = Math.abs(upY - downY);

//                Log.d(TAG, "抬起后 计算移动的x:" + upAbsX + ",======> " + upAbsY);

                if (upAbsX < 10 && upAbsY < 10)
                    movePlayVideo(ev);

                break;

        }

//        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
//            Toast.makeText(this, "触摸事件已捕获", Toast.LENGTH_SHORT).show();
//        }
        return super.dispatchTouchEvent(ev);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
//            case MotionEvent.ACTION_DOWN:
//
////                engine.setOptionString(engineHandler, SpeechEngineDefines.PARAMS_KEY_TTS_TEXT_STRING, "哈哈哈  我来也!");
//
//                startX = (int) event.getX();
//                startY = (int) event.getY();
//                Log.d("TouchRead", "按下");
//                break;
//
//            case MotionEvent.ACTION_MOVE:
//                Log.d("TouchRead", "移动");
//
//                moveX = (int) event.getX();
//                moveY = (int) event.getY();
//
//
//                if (layout == null) {
//                    layout = textView.getLayout();
//                }
//
//                if (layout == null) {
//                    return super.onTouchEvent(event);
//                }
//
//                int moveOffset = layout.getOffsetForHorizontal(layout.getLineForVertical(startY), startX);
//
//                if (moveX > startX) {
//                    Log.d("TouchRead", "向右滑动");
//
//                    Selection.setSelection(spannableText, moveOffset, moveOffset + 1);
//                } else if (moveX < startX) {
//                    Log.d("TouchRead", "向左滑动");
//                }
//
//                break;

            case MotionEvent.ACTION_UP:

                Log.d("TouchRead", "抬起");
//                movePlayVideo(event);


//                int start = Math.min(textView.getSelectionStart(), textView.getSelectionEnd());
//                int end = Math.max(textView.getSelectionStart(), textView.getSelectionEnd());
//                CharSequence selectedText = textView.getText().subSequence(start, end);
//                Log.d(TAG, "内容：" + selectedText);

                break;
        }


        return super.onTouchEvent(event);
    }

    private void movePlayVideo(MotionEvent event) {

        int x = (int) event.getX();
        int y = (int) event.getY();
        int[] location = new int[2];
        textView.getLocationOnScreen(location);
        int left = location[0];
        int top = location[1];
        Log.e(TAG, "textview在屏幕中的位置:left: " + left + " top: " + top);
        int right = left + textView.getWidth();
        int bottom = top + textView.getHeight();
        if (x >= left && x <= right && y >= top && y <= bottom) {
            // 计算点击位置在文本中的偏移量
            Layout layout = textView.getLayout();

            Paint paint = textView.getPaint();
            float charWidth = 0;
            if (CommUtils.isChinese()) {
                charWidth = paint.measureText("人"); // 以字符 '人' 的宽度作为参考
            } else {
                charWidth = paint.measureText("a");
            }

            float horiz = x - left - charWidth / 2;
            if (horiz < 0) {
                horiz = 0;
            }
            int offset = layout.getOffsetForHorizontal(layout.getLineForVertical(y - top), horiz);

            String text = textView.getText().toString();
            if (offset >= 0 && offset < text.length()) {
                String clickedText = text.substring(offset);
                int endIndex = clickedText.indexOf("\n");
                if (endIndex != -1) {
                    clickedText = clickedText.substring(0, endIndex);
                }

                if (!TextUtils.isEmpty(clickedText)) {
                    clickedText = clickedText.substring(0, 1);
                }
//                        textToSpeech.speak(clickedText, TextToSpeech.QUEUE_FLUSH, null);

                if (CommUtils.isChinese()) {
                    //中文
                    stop();
                    showPinyin(clickedText);
                    speak(clickedText);
                    Log.d(TAG, "位置,x: " + x + ",y: " + y + ",left: " + left + ",top: " + top + ",right: " + right + ",bottom: " + bottom + ",offset: " + offset + ",clickedText: " + clickedText);

                } else {

                    //英文
                    boolean englishChar = CommUtils.isEnglishChar(clickedText);

                    if (!englishChar)
                        return;
                    String englishWord = clickedText;

                    int beforeOffset = offset;
                    int afterOffset = offset;
                    //Log.d(TAG, "offset:" + offset);
                    String beforeTxt = "";
                    while (--beforeOffset > 0 && CommUtils.isEnglishChar(text.substring(beforeOffset, beforeOffset + 1))) {

                        //Log.d(TAG, "beforeOffset: " + beforeOffset);
                        beforeTxt = text.substring(beforeOffset, beforeOffset + 1);
                        englishWord = beforeTxt + englishWord;
                    }

                    while (++afterOffset < text.length() && CommUtils.isEnglishChar(text.substring(afterOffset, afterOffset + 1))) {
                        englishWord = englishWord + text.substring(afterOffset, afterOffset + 1);
                    }


                    //是英文字符， 再判断前后是否是
                    //String beforeTxt = text.substring(offset -1, offset);
                    Log.d(TAG, "英文单词是 :::" + englishWord);
                    stop();
                    showPinyin(englishWord);
                    speak(englishWord);

                }


            }
        }
    }

    private Dialog cDialog;
    private TextView tvChineseText;
    private TextView tvPinyinText;
    private Button btnCloseDialog;
    private ImageView ivRefresh;

    private void showPinyin(String clickedText) {


        Log.d(TAG, "开始获取拼音");
        String pinyin = PinyinUtil.getPinyin(clickedText);
        Log.e(TAG, "拼音===>>" + pinyin);

        // 创建自定义对话框
        if (mDialog == null) {
            mDialog = new Dialog(MainActivity.this);
            mDialog.setContentView(R.layout.layout_dialog_show);

            // 获取布局中的控件
            tvChineseText = mDialog.findViewById(R.id.tv_chinese_text);
            tvPinyinText = mDialog.findViewById(R.id.tv_pinyin_text);
            btnCloseDialog = mDialog.findViewById(R.id.btn_close_dialog);
            ivRefresh = mDialog.findViewById(R.id.ivRefresh);
        }


        ivRefresh.setOnClickListener(v -> {
            speak(clickedText);
        });
        // 设置文字和拼音
        if (CommUtils.isChinese())
            tvChineseText.setText(clickedText);
        else
            tvChineseText.setText("");
        tvPinyinText.setText(pinyin);

        // 设置关闭按钮点击事件
        btnCloseDialog.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mDialog.dismiss();
            }
        });

        // 显示对话框
        mDialog.show();
        Log.d(TAG, "显示拼音框");
    }


    @Override
    protected void onDestroy() {
        if (mSpeechSynthesizer != null) {
            mSpeechSynthesizer.stop();
            mSpeechSynthesizer.release();
            mSpeechSynthesizer = null;
            Log.d(TAG, "释放资源成功");
        }
        super.onDestroy();
    }

}